package code.util;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.jdom.Element;

import code.domain.CodeFile;
import code.domain.Structure;
import code.domain.XMLBean;
import code.xml.XMLSourceConfig;
/**
 * XML模板配置文件工具类
 * @author puxin.zhang
 *
 */
public class XMLUtils {
	/**
	 * 保存 生成文件目录结构和模板文件的Map<key=生成文件目录的id, value=生成的目录结构（包括模板文件）>
	 */
	private static Map<String, Structure> structureMap;
	/**
	 * 载入配置文件，并生成目录结构Map
	 */
	private static synchronized void loadStructures(){
		if(structureMap == null){
			Map<String, Structure> map = new HashMap<String, Structure>();
			XMLSourceConfig config = (XMLSourceConfig) CodeGeneratorContext.getBean("XMLSourceConfig");
			List<Element> nodes = config.getChildElements("structures.structure");
			for (Element node : nodes) {
				String structureId = node.getAttributeValue("id");
				Structure structure = generateStructure(node, "");	
				structure.setId(structureId);
				map.put(structureId, structure);
			}
			structureMap = map;
		}
	}
	/**
	 * 递归取目录结构
	 * @param structureNode
	 * @param parentPath
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static Structure generateStructure(Element structureNode, String parentPath){
		Structure structure = new Structure();
		structure.setPath(parentPath + File.separator + structureNode.getName());
		structure.setName(structureNode.getName());
		
		List<Structure> dirs = new ArrayList<Structure>();
		List<CodeFile> files = new ArrayList<CodeFile>();
		
		List<Element> childNodes = structureNode.getChildren();
		for (Element childNode : childNodes) {
			if(childNode.getName().equals("file")){
				CodeFile file = new CodeFile();
				file.setNamerules(childNode.getAttributeValue("namerule"));
				file.setTemplate(childNode.getAttributeValue("ftl"));
				file.setMerge(StringUtils.equalsIgnoreCase(childNode.getAttributeValue("isMerge"), "true"));
				files.add(file);
			}
			else{
				Structure dir = generateStructure(childNode, structure.getPath());
				dirs.add(dir);
			}				
		}		
		structure.setFiles(files);
		structure.setChildDirs(dirs);
		return structure;
	}
	/**
	 * 根据目录结构ID获得生成文件的目录结构和使用的模板
	 * @param id 目录结构ID
	 * @return
	 */
	public static Structure getStructure(String id){
		if(structureMap == null){
			loadStructures();
		}
		return structureMap.get(id);
	}
	/**
	 * 获得需要生成目录的数据源Bean对象列表
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List<XMLBean> getBeans(){
		XMLSourceConfig config = (XMLSourceConfig) CodeGeneratorContext.getBean("XMLSourceConfig");
		List<XMLBean> beans = new ArrayList<XMLBean>();
		List<Element> elements = config.getChildElements("beans.bean");
		for (Element beanNode : elements) {
			XMLBean bean = new XMLBean();
			bean.setModelName(beanNode.getAttributeValue("modelName"));
			bean.setTableName(beanNode.getAttributeValue("tableName"));
			bean.setPackageName(beanNode.getAttributeValue("package"));
			bean.setIsReplace(beanNode.getAttributeValue("isReplace"));
			
			Map<String, String> codePathMap = new HashMap<String, String>();
			List<XMLBean> subBeans = new ArrayList<XMLBean>();
			List<Element> childElements = beanNode.getChildren();
			for (Element child : childElements) {
				if(child.getName().equals("subBean")){
					XMLBean subBean = new XMLBean();
					subBean.setTableName(child.getAttributeValue("tableName"));
					subBean.setModelName(child.getAttributeValue("modelName"));
					subBean.setParentKey(child.getAttributeValue("parentKey"));
					
					subBean.setPackageName(beanNode.getAttributeValue("package"));
					subBean.setIsReplace(beanNode.getAttributeValue("isReplace"));
					
					subBeans.add(subBean);
				}
				else{
					codePathMap.put(child.getName(), child.getTextTrim());
				}
			}
			if(!subBeans.isEmpty()){
				for (XMLBean subBean : subBeans) {
					subBean.setCodePath(codePathMap);
				}
			}
			bean.setCodePath(codePathMap);
			bean.setSubBeans(subBeans);
			beans.add(bean);
		}
		return beans;
	}
}
